package labilabyrinth.game;

import java.util.ArrayList;

import labilabyrinth.activity.GameActivity;
import labilabyrinth.enums.GameState;
import labilabyrinth.game.R;
import labilabyrinth.level.editor.LevelManager;
import labilabyrinth.serializable.FinishHole;
import labilabyrinth.serializable.Hole;
import labilabyrinth.serializable.Level;
import labilabyrinth.serializable.MyRectF;
import android.content.Context;
import android.graphics.*;
import android.hardware.*;
import android.util.Log;
import android.view.*;

/*
 * tato trieda sluzi na vykreslovanie plochy a gulicky
 * */
public class GameSurface extends SurfaceView implements SurfaceHolder.Callback, SensorEventListener {
	public static final int SENSOR_DELAY = SensorManager.SENSOR_DELAY_UI;
	public static final float SURFACE_FRICTION = 120.0f;
	public static int ELEM_SIZE_FACTOR = 12;// R.integer.elem_size_factor;
	
	// referencie na objekty
	private GameLoop gameLoop;
	private Paint paint;
	private Bitmap surface;
	private Ball ball;
	private WindowManager windowManager;
	private Display display;
	private Bitmap finishHoleBmp;
	private Bitmap deadlyHoleBmp;
	// sensory
	private SensorManager manager;
	private Sensor acceleroMeter;
	
	public GameState state;
	private float axisX; // zrychlenie v x osi
	private float axisY; // zrychlenie v y osi
	
	private int elementsSize; // reprezentuje jednotku velkosti na ploche 1element najmensia jednotka a to je 1/15 z sirku hracej plochy
	private Level currentLevel;
	private ArrayList<RectF> obstacles;

	public float round(float n, int accuraccy) {
		int d = (int) Math.pow(10, accuraccy);
		float res = n * d;
		res = Math.round(res) / (float) d;
		return res;
	}

	/**
	 * @return zrychlenie v m/s v osi X
	 */
	public float getAxisX() {
		return axisX;
	}

	/**
	 * @return zrychlenie v m/s v osi Y
	 */
	public float getAxisY() {
		return axisY;
	}

	public void setAxisX(float axisX) {
		this.axisX = round(axisX, 5);
	}

	public void setAxisY(float axisY) {
		this.axisY = round(axisY, 5);
	}

	public int getElementsSize() {
		return elementsSize;
	}

	public Level getCurrentLevel() {
		return this.currentLevel;
	}
	

	public ArrayList<RectF> getObstacles() {
		return obstacles;
	}

	public GameSurface(Context c) {
		super(c);
		getHolder().addCallback(this);
		windowManager = (WindowManager) c.getSystemService(GameActivity.WINDOW_SERVICE);
		manager = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);
		acceleroMeter = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
		display = windowManager.getDefaultDisplay();
		paint = new Paint();
		paint.setColor(Color.WHITE);
		elementsSize =  display.getWidth()/ ELEM_SIZE_FACTOR;
		
		surface = BitmapFactory.decodeResource(c.getResources(), R.drawable.game_surface_480x800);
		Bitmap tempBmp = BitmapFactory.decodeResource(c.getResources(), R.drawable.hole);
			deadlyHoleBmp = Bitmap.createScaledBitmap(tempBmp,elementsSize+4,elementsSize+4 , true);
		tempBmp = BitmapFactory.decodeResource(c.getResources(), R.drawable.finish_hole);
			finishHoleBmp = Bitmap.createScaledBitmap(tempBmp,elementsSize+4,elementsSize+4 , true);
		state = GameState.PAUSED;
	}

	public void loadObstacles(){
		obstacles = new ArrayList<RectF>();
		for(MyRectF m:currentLevel.getObstacles()){
			obstacles.add(new RectF(m.left, m.top, m.right, m.bottom));
		}
		Log.d("lvl","obstacles nacitane");
	}
	
	public boolean loadLevel(String lName){
		try{
			LevelManager lm = new LevelManager(this.getContext());
			currentLevel = lm.loadLevel(lName);
			if(currentLevel == null)
				return false;
			loadObstacles();
			return true;
		}catch(Exception e){
			Log.d("lvl","nacitavam lvl: "+currentLevel.toString());
			return false;
		}
	}

	/*
	 * vyrkresli hrany plochy bumpers tmavo hnedou farbou RGB(35,16,2)
	 */
	private void drawObstacles(Canvas canvas) {
		paint.setColor(Color.parseColor("#ffdab9"));
		for (RectF r : obstacles) {
			canvas.drawRect(r, paint);
		}
	}

	/*
	 * vyrkresli diery na ploche
	 */
	private void drawHoles(Canvas canvas) {
		for (Hole h : currentLevel.getHoles()) {
			if(h instanceof FinishHole)
				h.draw(canvas,finishHoleBmp);
			else
				h.draw(canvas,deadlyHoleBmp);
		}
	}

	/*
	 * vykresli hraciu plochu bez gulicky
	 */
	private void drawGameSurface(Canvas canvas) {
		canvas.drawBitmap(surface, 0, 0, paint);
		this.drawHoles(canvas);
		this.drawObstacles(canvas);
	}

	/*
	 * Sluzi na kreslenie neustale volany threadom od vytvorenia
	 */
	public void onDraw(Canvas canvas, float dT) {
		this.drawGameSurface(canvas);
		ball.draw(canvas);
		switch (state) {
		case PAUSED:
			paint.setColor(Color.WHITE);
			paint.setTextSize(40);
			canvas.drawText("GAME PAUSED",getWidth()/2 - 120,getHeight()/2, paint);
			break;
		case LEVELCOMPLETED:
			paint.setColor(Color.GREEN);
			paint.setTextSize(40);
			canvas.drawText("LEVEL COMPLETED",getWidth()/2 - 160,getHeight()/2, paint);
			break;
		case LEVELFAILED:
			paint.setColor(Color.RED);
			paint.setTextSize(40);
			canvas.drawText("LEVEL FAILED",getWidth()/2 - 120,getHeight()/2, paint);
			break;
		default:
			/*// DEBUG
			paint.setColor(Color.WHITE);
			paint.setTextSize(20);
			canvas.drawText("VX: " + ball.getVelocityVector().x, 50, 150, paint);
			canvas.drawText("VY: " + ball.getVelocityVector().y, 50, 180, paint);
			break;*/
		}			
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}

	public void surfaceCreated(SurfaceHolder holder) {
		startNewGame();
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		boolean retry = true;
		gameLoop.setRunning(false);
		while (retry) {
			try {
				gameLoop.join();
				retry = false;
			} catch (InterruptedException e) {
				// we will try it again and again...
			}
		}
	}

	public void startNewGame() {
		ball = new Ball(elementsSize, this);
		Log.d("lvl", "gulicka: "+ball.toString());
		if(currentLevel != null)
			ball.setPosition(currentLevel.getBallPosition().x,currentLevel.getBallPosition().y);
		gameLoop = new GameLoop(this.getHolder(), this, ball);
		gameLoop.setRunning(true);
		gameLoop.start();
	}

	public void pauseGame() {
		if(state.equals(GameState.PAUSED))
			return;
		state = GameState.PAUSED;
		manager.unregisterListener(this);
	}
	
	public void resumeGame() {
		if(state.equals(GameState.RUNNING))
			return;
		if (manager.registerListener(this, acceleroMeter, SENSOR_DELAY)) {
			Log.d("SensorReader", "AcceleroMeter ready");
		} else {
			Log.d("SensorReader", "No acceptable hardware found.");
			manager.unregisterListener(this);
		}
		state = GameState.RUNNING;
	}

	public void onAccuracyChanged(Sensor sensor, int accuracy) {
	}

	public void onSensorChanged(SensorEvent event) {
		if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
			return;
		switch (display.getRotation()) {
		case Surface.ROTATION_0:
			setAxisX(-event.values[0]);
			setAxisY(event.values[1]);
			break;
		case Surface.ROTATION_90:
			setAxisX(event.values[1]);
			setAxisY(event.values[0]);
			break;
		case Surface.ROTATION_180:
			setAxisX(event.values[0]);
			setAxisY(-event.values[1]);
			break;
		case Surface.ROTATION_270:
			setAxisX(-event.values[1]);
			setAxisY(-event.values[0]);
			break;
		}
	}

}
